
#include "RtBase.h"
#include "RtDataBlock.h"

#ifdef RT_WIN32
	#include "Psapi.h"
#endif// RT_WIN32

void DumpCurrentMemory()
{
#ifdef RT_WIN32
	typedef BOOL (WINAPI *GetProcessMemoryInfoFunc)(HANDLE , PPROCESS_MEMORY_COUNTERS , DWORD );
	static GetProcessMemoryInfoFunc m_pGetProcessMemoryInfo = NULL;
	static HMODULE m_hPsapi = NULL;
	if (!m_pGetProcessMemoryInfo)
	{
		m_hPsapi = NULL;
		m_hPsapi = LoadLibraryA("Psapi.dll");
		if (m_hPsapi)
		{
			m_pGetProcessMemoryInfo = (GetProcessMemoryInfoFunc)GetProcAddress(m_hPsapi, "GetProcessMemoryInfo");
		}	
	}
	if (m_pGetProcessMemoryInfo)
	{
		PROCESS_MEMORY_COUNTERS pmc;
		pmc.cb = sizeof(PROCESS_MEMORY_COUNTERS);
		if ( m_pGetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)) )
		{
			RT_INFO_TRACE( "DumpCurrentMemory, mem = "<< (pmc.WorkingSetSize / 1024) 
				<<" KB, virtual mem = "<< (pmc.PagefileUsage / 1024));
		}
    }
#endif// RT_WIN32
}

RtResult CRtDataBlock::
CreateInstance(CRtDataBlock *&aDb, DWORD aSize, LPCSTR aData)
{
	RT_ASSERTE(!aDb);
	RT_ASSERTE_RETURN(aSize > 0, RT_ERROR_INVALID_ARG);

	// alloc sizeof(CRtDataBlock) and <aSize> at one time.
	std::allocator<char> allocChar;
	char *pBuf = allocChar.allocate(sizeof(CRtDataBlock) + aSize, NULL);
	if (!pBuf)
	{
		RT_ERROR_TRACE("CRtDataBlock::CreateInstance, allocate failed! aSize="<<aSize);
		DumpCurrentMemory();
		return RT_ERROR_OUT_OF_MEMORY;
	}

	// call constructor function of CRtDataBlock.
	LPSTR pDbData = pBuf + sizeof(CRtDataBlock);
	if (aData)
		::memcpy(pDbData, aData, aSize);
	new (pBuf) CRtDataBlock(aSize, pDbData);
	
	aDb = static_cast<CRtDataBlock*>(static_cast<void*>(pBuf));
	aDb->AddReference();
	return RT_OK;
}

CRtDataBlock::CRtDataBlock(DWORD aSize, LPSTR aData)
	: m_dwSize(aSize)
	, m_pData(aData)
{
}

CRtDataBlock::~CRtDataBlock()
{
	// Don't delete m_pData because it is combiled with <CRtDataBlock>.
}

void CRtDataBlock::OnReferenceDestory()
{
	DWORD dwLen = m_dwSize + sizeof(CRtDataBlock);
	this->~CRtDataBlock();

	std::allocator<char> allocChar;
	allocChar.deallocate(static_cast<char*>(static_cast<void*>(this)), dwLen);
}
